package com.lqk.demo.concurrencytools.threadpool.juc.aqs;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

import static com.lqk.demo.n2.util.Sleeper.sleep;

/**
 * @author lqk
 * @date 2022/1/11 13:02
 *
 * 全称是 AbstractQueuedSynchronizer，是阻塞式锁和相关的同步器工具的框架
 * 特点：
 *  用 state 属性来表示资源的状态（分独占模式和共享模式），子类需要定义如何维护这个状态，控制如何获取
 *  锁和释放锁
 *      getState - 获取 state 状态
 *      setState - 设置 state 状态
 *      compareAndSetState - cas 机制设置 state 状态
 *      独占模式是只有一个线程能够访问资源，而共享模式可以允许多个线程访问资源
 *  提供了基于 FIFO 的等待队列，类似于 Monitor 的 EntryList
 *  条件变量来实现等待、唤醒机制，支持多个条件变量，类似于 Monitor 的 WaitSet
 */

@Slf4j
public class TestAQS {
    public static void main(String[] args) {
        MyLock lock = new MyLock();
        new Thread(()->{
            lock.lock();
            try {
                log.debug("locked...");
                sleep(1);
            } finally {
                log.debug("unlocking...");
                lock.unlock();
            }
        },"t1").start();

        new Thread(()->{
            lock.lock();
            try {
                log.debug("locked...");
            } finally {
                log.debug("unlocking...");
                lock.unlock();
            }
        },"t2").start();
    }
}

// 自定义锁 (不可重入锁)
class MyLock implements Lock {

    // 同步器类
    // 独占锁
    class MySync extends AbstractQueuedSynchronizer {
        // 尝试获得锁
        @Override
        protected boolean tryAcquire(int arg) {
            if (compareAndSetState(0,1)) {
                // 加上了锁, 并设置 owner 为当前线程
                setExclusiveOwnerThread(Thread.currentThread());
            }
            return false;
        }

        @Override
        protected boolean tryRelease(int arg) {
            // state 用 volatile 修饰, 所以为了使 exclusiveOwnerThread 保证可见性, 放到 setState 前
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        // 是否持有独占锁
        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }

        public Condition newCondition() {
            // ConditionObject() 是 AbstractQueuedSynchronizer 的内部类
            return new ConditionObject();
        }
    }

    private MySync sync = new MySync();

    // 加锁 (不成功会进入等待队列)
    @Override
    public void lock() {
        // 内部会调用 tryAcquire
        sync.acquire(1);
    }

    // 加锁 , 可打断
    @Override
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    // 尝试加锁 (尝试加锁一次, 失败就会返回false, 不会进入等待队列)
    @Override
    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    // 尝试加锁, 带超时时间 (尝试加锁一次, 失败就会返回false, 不会进入等待队列)
    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1,unit.toNanos(time));
    }

    // 解锁
    @Override
    public void unlock() {
        // release 会调用 unpark 唤醒阻塞线程, tryRelease不会
        sync.release(1);
    }

    // 创建条件变量 (调用 await() 后进入的地方)
    @Override
    public Condition newCondition() {
        return sync.newCondition();
    }
}
